// 先看看一个简单的例子
fn main() {
    // String内存上分配到堆上的
    let s1 = gives_own();
    println!("s1 = {s1}");

    let s2 = String::from("hell0");
    let s3 = takes_and_gives_back(s2);
    // println!("s2 = {s2}"); //这里如果再次调用s2会报错，因为s2的所有权已经给s3了，所以s2已经不能使用了

    // 如果想象使用，就需要用到引用
    // 引用的用法：&
    let mut s3 = String::from("hello");
    // 这里只能用&，直接使用s3会报错
    let len = calcute_length(&s3);
    println!("len = {len}");
    // &mut就是借用
    modify_s(&mut s3);
    println!("s3 = {s3}");

    let ms = &mut s3;
    // println!("s3 = {s3}"); //这里会报错，因为s3已经被ms变成可变，此时再次重新调用s3时会报错
    println!("ms = {ms}");
    println!("s3 = {s3}");


    // 引用难点例子
    let mut s4 = String::from("hello");
    let r1 = &s4; // 这里做了不可变引用 此时s4就变成了不可变变量
    let r2 = &s4; // 这里也做了不可变引用
    let r3 = &mut s4; // 将不可变变量变成可变引用，类型发生变化，导致报错

    println!("r1 = {r1}"); // 这里做了不可变引用 此时s4就变成了不可变变量
    println!("r2 = {r2}"); // 这里也做了不可变引用
    // println!("r3 = {r3}"); // 将不可变变量变成可变引用，类型发生变化，导致报错
}
// 这个函数是引用的例子
// 应用：让我们创建一个指向值的应用，但是并不拥有它，因为不拥有这个值，所以当引用离开其值只想的作用域后也不会被丢弃
fn calcute_length(s: &String) -> usize {
    s.len()
}

fn modify_s(s: &mut String) {
    s.push_str(", word!");
}

fn takes_and_gives_back(s: String) -> String {
    s
}

fn gives_own() -> String{
    let s = String::from("hello");
    s
}
